// Created by Roman Novitsky on 24.04.2009


#region Imported Namespaces


using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

using AvalonDock;


#endregion


namespace WtfManager.Controls
{
  /// <summary>
  /// Interaction logic for WtfDocumentContent.xaml
  /// </summary>
  public class WtfDocumentContent: DocumentContent
  {
    #region Fields


    private static readonly List<WeakReference> _contentControls = new List<WeakReference>();

    public static DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object),
                                                                                typeof(WtfDocumentContent),
                                                                                new PropertyMetadata(DataPropertyChanged));

    public static DependencyProperty DataTemplateProperty = DependencyProperty.Register("DataTemplate",
                                                                                        typeof(DataTemplate),
                                                                                        typeof(WtfDocumentContent),
                                                                                        new PropertyMetadata(
                                                                                          DataTemplatePropertyChanged));


    public static DependencyProperty IsDefaultFocusedElementProperty =
      DependencyProperty.RegisterAttached("IsDefaultFocusedElement", typeof(bool), typeof(WtfDocumentContent),
                                          new PropertyMetadata(IsDefaultFocusedElementPropertyChanged));


    private readonly ContentControl _contentControl;


    #endregion


    #region Constructors/Finalizers


    public WtfDocumentContent()
    {
      _contentControl = new ContentControl();
      Content = _contentControl;

      var reference = new WeakReference(_contentControl);
      _contentControls.Add(reference);
    }


    #endregion


    #region Properties/Indexers


    public object Data
    {
      get
      {
        return GetValue(DataProperty);
      }
      set
      {
        SetValue(DataProperty, value);
      }
    }


    public DataTemplate DataTemplate
    {
      get
      {
        return (DataTemplate)GetValue(DataTemplateProperty);
      }
      set
      {
        SetValue(DataTemplateProperty, value);
      }
    }


    #endregion


    #region Methods


    private static void IsDefaultFocusedElementPropertyChanged(DependencyObject dependencyObject,
                                                               DependencyPropertyChangedEventArgs e)
    {
      if (dependencyObject is FrameworkElement)
      {
        var frameworkElement = (FrameworkElement)dependencyObject;

        if (!frameworkElement.IsLoaded)
        {
          frameworkElement.Loaded += DefaultFocusedElementInitialized;

          return;
        }
      }

      SetDefaultFocusedElement(dependencyObject);
    }


    private static void SetDefaultFocusedElement(DependencyObject dependencyObject)
    {
      DependencyObject logical = dependencyObject;

      while (true)
      {
        DependencyObject parent = LogicalTreeHelper.GetParent(logical);

        if (parent != null)
        {
          logical = parent;
        }
        else
        {
          break;
        }
      }

      var deadReferences = new List<WeakReference>();

      foreach (WeakReference reference in _contentControls)
      {
        if (!reference.IsAlive)
        {
          deadReferences.Add(reference);
          continue;
        }

        var contentControl = (ContentControl)reference.Target;

        if (!contentControl.IsLoaded)
        {
          continue;
        }

        DependencyObject contentPresenter = VisualTreeHelper.GetChild(contentControl, 0);

        if (!(contentPresenter is ContentPresenter))
        {
          continue;
        }

        int childrenCount = VisualTreeHelper.GetChildrenCount(contentPresenter);

        for (int i = 0; i < childrenCount; i++)
        {
          object contentPresenterChild = VisualTreeHelper.GetChild(contentPresenter, i);

          if (contentPresenterChild != logical)
          {
            continue;
          }

          var documentContent = contentControl.Parent as WtfDocumentContent;

          if (documentContent != null)
          {
            documentContent.DefaultElement = dependencyObject as IInputElement;
            return;
          }
        }
      }

      foreach (WeakReference deadReference in deadReferences)
      {
        _contentControls.Remove(deadReference);
      }
    }


    private static void DefaultFocusedElementInitialized(object sender, EventArgs e)
    {
      if (sender != null)
      {
        SetDefaultFocusedElement((DependencyObject)sender);
      }
    }


    private static void DataPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
      var documentContent = (WtfDocumentContent)dependencyObject;
      object newValue = e.NewValue;

      documentContent._contentControl.Content = newValue;
      documentContent.DataContext = newValue;

      if (documentContent.Icon != null && documentContent.Icon is FrameworkElement)
      {
        var element = (FrameworkElement)documentContent.Icon;
        element.DataContext = newValue;
      }
    }


    private static void DataTemplatePropertyChanged(DependencyObject dependencyObject,
                                                    DependencyPropertyChangedEventArgs e)
    {
      var documentContent = (WtfDocumentContent)dependencyObject;
      documentContent._contentControl.ContentTemplate = (DataTemplate)e.NewValue;
    }


    public static void SetIsDefaultFocusedElement(DependencyObject element, bool value)
    {
      if (element == null)
      {
        throw new ArgumentNullException("element");
      }

      element.SetValue(IsDefaultFocusedElementProperty, value);
    }


    public static bool GetIsDefaultFocusedElement(DependencyObject element)
    {
      if (element == null)
      {
        throw new ArgumentNullException("element");
      }
      return (bool)element.GetValue(IsDefaultFocusedElementProperty);
    }


    #endregion
  }
}